#include "wds_player.h"
#include "wds_game.h"
#include "wds_gun.h"
#include "wds_sounds.h"
#include "wds_pickup_manager.h"
#include "wds_enemy_collection.h"
#include "wds_enemy.h"

#include "graphics/graphics_util.h"

WDSPlayer::WDSPlayer() : WDSLifeObject(),
						m_pGame(NULL),
						m_IsShooting(false),
						m_pGun(NULL),
						m_GetHitIndicatorDelay(0),
						m_pLaserSight(NULL)						
						
{
	m_Sprite.Create("img/player.png");
	
	m_Facing.SetTurnSpeed(360.0f * 1.5f);
	m_Facing.SetSnap(false);

	m_Movement.SetCurrent(math::Vec2(0.5f,0.5f));
	m_Speed = 0.1f;
	m_Movement.SetMoveSpeed(m_Speed);	
	
	//WDSBullet::BULLET_TYPES Type, 
	//					int GroupCount, 
	//					float BulletFrequency,
	//					float DelayAfterBulletGroup,
	//					bool IsPlayer


	m_pGun = new WDSGun(WDSGun::GUN_TYPE_ASSAULT_RIFLE, m_Skill.m_ExtraAmmo);

	//m_pBulletManager = new WDSBulletCollection(WDSBullet::BULLET_TYPE_MEAN_MINI_GUN, 
	//									10, 1.0f, 1.0f, true );

	//m_pBulletManager = new WDSBulletCollection(WDSBullet::BULLET_TYPE_JACK_HAMMER, 
	//									16, 0.15f, 1.5f, true );
	
	m_UI.Init(this);

	m_pLaserSight = new WDSPlayer::LaserSight();	

}

void	WDSPlayer::Render(const math::Vec2& Offset,float Scale)
{
	if(m_GetHitIndicatorDelay > 0)
	{
		m_Sprite.m_Color = ColorfRGBA(1.0f,0.5f,0.5f,1.0f);
	}
	else
	{
		m_Sprite.m_Color = ColorfRGBA(1.0f,1.0f,1.0f,1.0f);
	}
	WDSLifeObject::Render(Offset,Scale * 1.25f);

	if(m_pGun)
	{
		const math::Vec2 Pos = GetPos() + ( m_Facing.GetForwardW2H() * (m_Sprite.m_SizeOriginal.x * 0.5f));
		m_pGun->Render(Pos, Offset, m_Facing.GetAngle(), Scale);
		//m_pBulletManager->RenderDebug(Offset, Scale);
	}

	m_Shield.Render(Offset,GetPos(), Scale);
	if(m_pLaserSight)
	{
		m_pLaserSight->Render(this,Offset, Scale);
	}

}

void	WDSPlayer::RenderShadow(const math::Vec2& Offset,float Scale)
{
	WDSEnemyManager::Instance().RenderShadowInPos(GetPos(), m_Facing.GetAngle(), Offset, Scale);
}

WDSPlayer::~WDSPlayer()
{
	UTIL_SAFE_DELETE(m_pGun);
	UTIL_SAFE_DELETE(m_pLaserSight);

}

void	WDSPlayer::SetGame(WDSGame* pGame, const math::Vec2& MinBoundary, const math::Vec2& MaxBoundary)
{ 
	m_pGame = pGame; 
	m_Movement.SetMinMax(MinBoundary + m_Sprite.m_SizeOriginal * 0.5f ,MaxBoundary - m_Sprite.m_SizeOriginal * 0.5f);
}

void	WDSPlayer::Tick(float World_dt, float dt, const math::Vec2& Offset, float Scale)
{
	m_UI.Tick(dt, this);
	
	WDSLifeObject::Tick(dt);
	if(!m_IsAlive)
		return;

	if( m_GetHitIndicatorDelay > 0)
		m_GetHitIndicatorDelay -= dt;

	const float MoveBonus_dt = m_BonusMoveSpeed.Tick(dt);
	if(MoveBonus_dt > 0)
		m_Movement.Tick( dt * MoveBonus_dt);

	math::Vec2 TempPos = GetPos() - Offset;
	math::Vec2 TempDir = m_MousePos;
	TempPos.y /= GraphicsUtil::W2H; 
	TempDir.y /= GraphicsUtil::W2H; 

	m_Facing.SetTarget(math::Facing::AngleFromTo(TempPos , TempDir));
	
	//if(m_pGame)
	//	m_pGame->SetOffset(m_Movement.GetPos());
 
	//math::Vec2 Dir = m_Movement.VectorFromAngle(m_Rotation);
	//Dir.y *= GraphicsUtil::W2H;
	
	
	if(m_pGame)
		m_pGame->UpdateOffset(GetPos());
	
	
	if(m_pGun)
	{
		m_pGun->Tick(World_dt);
		m_pGun->ShootTick(World_dt * m_BonusGunSpeed.Tick(World_dt), m_Skill, Offset);
	}
	
	if(m_IsShooting)
	{
		m_IsShooting = false;
		
		math::Vec2 Dir = m_Facing.GetForwardW2H();		
		m_pGun->Shoot(
						this,
						1.0f,
						GetPos() +( Dir * m_Sprite.m_SizeOriginal.x * 0.5f ),									
						m_Facing.GetAngle(),							
						Offset,
						WDSSounds::SFX_NONE
						);
	}
	
	const WDSPickup::PICKUP_TYPES PickupType = WDSPickupManager::Instance().HitTest(GetPos(), m_Sprite.m_SizeOriginal.x, Scale);
	if(PickupType > WDSPickup::PICKUP_TYPE_NONE)
		GotPickup(PickupType);

	m_Shield.Tick(dt);
	CheckSurrounding(Offset);

	if(m_Skill.m_Regeneration > 0.0f && m_Life < m_MaxLife && IsAlive())
	{
		m_Life += (dt * m_Skill.m_Regeneration);
		if( m_Life > m_MaxLife)
			m_Life = m_MaxLife;
	}
}

void		WDSPlayer::CheckSurrounding(const math::Vec2& Offset)
{
	std::vector<WDSEnemyCollection*> EnemyCollection;
	WDSEnemyManager::Instance().GetEnemyCollection(EnemyCollection);

	
	for(int i = 0; i < (int)EnemyCollection.size(); i++)
	{
		WDSEnemyCollection* pEnemyCollection = EnemyCollection[i];

		for(int j = 0; j < pEnemyCollection->GetCount(); j++)
		{
			WDSEnemy* pEnemy = pEnemyCollection->GetEnemyByIndex(j);

			if(!pEnemy->IsAlive())	// active? alive?
				continue;

			const float Dist = (pEnemy->GetPos() - GetPos()).Magnitude();			
			
			// bump here
			if( Dist < m_Sprite.m_SizeOriginal.x * 0.5f )
			{
				
				math::Vec2 Dir = pEnemy->GetPos() - GetPos();	
				const math::Vec2 CurrentDir =  m_Movement.GetTarget();

				//don't bump too much where I am going otherwise, it may look like movespeed is too much
				if( CurrentDir.x > 0 && Dir.x > 0 && Dir.x > CurrentDir.x)
					Dir.x = CurrentDir.x;
				else if( CurrentDir.x < 0 && Dir.x < 0 && Dir.x < CurrentDir.x)
					Dir.x = CurrentDir.x;
				if( CurrentDir.y > 0 && Dir.y > 0 && Dir.y > CurrentDir.y)
					Dir.y = CurrentDir.y;
				else if( CurrentDir.y < 0 && Dir.y < 0 && Dir.y < CurrentDir.y)
					Dir.y = CurrentDir.y;

				m_Movement.AddForce(Dir * -1.0f,1.0f,1.0f);
				pEnemy->AddForce(Dir ,1.0f,0.25f);
				
			}

		}
	}
	
}

void	WDSPlayer::OnMouseMove(const math::Vec2& From, const math::Vec2& To)
{
	
	//math::Vec2 ToPos = To;
	//ToPos.y *= GraphicsUtil::H2W;
	
	m_MousePos = To;
	
	
}

void	WDSPlayer::OnMouseDown(const math::Vec2& Pos)
{
	m_IsShooting = true;
}

void	WDSPlayer::OnMouseUp(const math::Vec2& Pos)
{

}

void	WDSPlayer::OnJoystickTilt(const math::Vec3& AxisState)
{

}

void	WDSPlayer::OnMOGAMotionEvent(float X,float Y)
{
	if(X == 0.0f && Y == 0.0f)
		m_Movement.Stop();
	else
	{
		X += GetPos().x;
		Y += GetPos().y;
		//if(m_Movement.GetIsUnderForce())
		//{
			//m_Movement.SetMoveSpeed(m_Speed * 0.25f);	// slow down
		//}
		//else
		//{
		//	m_Movement.SetMoveSpeed(m_Speed);
		//}
		m_Movement.SetTarget(math::Vec2(X,Y));	
	}
}

void	WDSPlayer::GotPickup(WDSPickup::PICKUP_TYPES PickupType)
{
	if( PickupType > WDSPickup::PICKUP_TYPE_GUNSTART &&
		PickupType < WDSPickup::PICKUP_TYPE_GUNEND)
	{
		GotPickupGun(PickupType);
		return;
	}

	switch(PickupType)
	{
		case WDSPickup::PICKUP_TYPE_1UP:
		break;

		case WDSPickup::PICKUP_TYPE_HEALTH:
			m_Life += m_MaxLife * 0.35f;
			if(m_Life > m_MaxLife)
				m_Life = m_MaxLife;
		break;

		case WDSPickup::PICKUP_TYPE_STAR:
		break;

		case WDSPickup::PICKUP_TYPE_SHIELD:
			m_Shield.Activate();
		break;		

		case WDSPickup::PICKUP_TYPE_NUKE:
			// pickup itself will handle it
		break;				
		
		case WDSPickup::PICKUP_TYPE_FIREBLAST:
			// pickup itself will handle it
		break;

		case WDSPickup::PICKUP_TYPE_FIREBULLETS:
		{
			const float DURATION = 10.0f;
			if(m_pGun)
				m_pGun->SetFireBulletDuration(DURATION);
		}
		break;

		case WDSPickup::PICKUP_TYPE_FLASHSTEP:
			if(m_pGame)
				m_pGame->ActivateSlowmotion();
		break;

		case WDSPickup::PICKUP_TYPE_FREEZE:
			// pickup itself will handle it						
		break;

		case WDSPickup::PICKUP_TYPE_MOVESPEED:
			m_BonusMoveSpeed.Activate();
		break;

		case WDSPickup::PICKUP_TYPE_WEAPONSPEED:
			m_BonusGunSpeed.Activate();
		break;

		


	}
}

void	WDSPlayer::GotDamaged(float Amount,WDSBullet* pBullet, bool Force)
{
	if(m_Life <= 0)
		return;

	if(m_Shield.IsActivating())
		return;

	m_GetHitIndicatorDelay = 0.25f;
		
	WDSLifeObject::GotDamaged(Amount,pBullet,Force);
}

void	WDSPlayer::MoveSpeedBonus::Activate()
{
	const float FLAHS_STEP_DURATION = 15.0f;
	
	m_CurrentMoveBonus = 0;;
	m_IsGoingUp = true;
	m_Counter = FLAHS_STEP_DURATION;
	if(!m_IsActivate)
		m_CurrentMoveBonus = 0.0f;

	m_IsActivate = true;;

}

float	WDSPlayer::MoveSpeedBonus::Tick(float dt)
{
	if(!m_IsActivate)
		return 0.0f;

	const float MAX_BONUS = 0.5f;

	if(m_IsGoingUp)
	{
		m_CurrentMoveBonus += ( dt * 2.0f);
		if(m_CurrentMoveBonus >= MAX_BONUS)
		{
			m_CurrentMoveBonus = MAX_BONUS;
			m_IsGoingUp = false;
		}
		return m_CurrentMoveBonus;
	}
	
	if(m_Counter > 0)
	{
		m_Counter -= dt;
	}	
	else if(m_CurrentMoveBonus > 0.0f)
	{
		m_CurrentMoveBonus -= dt;
		if(m_CurrentMoveBonus <= 0.0f)
		{
			m_CurrentMoveBonus = 0.0f;
			m_IsActivate = false;
		}
	}

	return m_CurrentMoveBonus;
	
}

void	WDSPlayer::GunSpeedBonus::Activate()
{
	const float BONUS_DURATION = 15.0f;
	const float MAX_BONUS = 2.0f;

	m_Bonus = MAX_BONUS;	
	m_Counter = BONUS_DURATION;
	m_IsActivate = true;;
}

float	WDSPlayer::GunSpeedBonus::Tick(float dt)
{
	if(!m_IsActivate)
		return 1.0f;
	
	if(m_Counter > 0)	
		m_Counter -= dt;		
	else
		m_IsActivate = false;		

	return m_Bonus;	
}

void	WDSPlayer::GotPickupGun(WDSPickup::PICKUP_TYPES PickupTypeGun)
{
	WDSGun* pNewGun = NULL;

	switch(PickupTypeGun)
	{
		case WDSPickup::PICKUP_TYPE_SHOTGUN:
			pNewGun = new WDSGun(WDSGun::GUN_TYPE_SHOTGUN, m_Skill.m_ExtraAmmo);
		break;

		case WDSPickup::PICKUP_TYPE_SAWEDOFFSHOTGUN:
			pNewGun = new WDSGun(WDSGun::GUN_TYPE_SAWED_OFF_SHOTGUN, m_Skill.m_ExtraAmmo);
		break;

		case WDSPickup::PICKUP_TYPE_SUBMACHINEGUN:
			pNewGun = new WDSGun(WDSGun::GUN_TYPE_SUBMACHINE, m_Skill.m_ExtraAmmo);
		break;

		case WDSPickup::PICKUP_TYPE_GAUSSGUN:
			pNewGun = new WDSGun(WDSGun::GUN_TYPE_GAUSS, m_Skill.m_ExtraAmmo);
		break;

		case WDSPickup::PICKUP_TYPE_MEANMINIGUN:
			pNewGun = new WDSGun(WDSGun::GUN_TYPE_MEAN_MINIGUN, m_Skill.m_ExtraAmmo);
		break;

		case WDSPickup::PICKUP_TYPE_FLAMETHROWER:
			pNewGun = new WDSGun(WDSGun::GUN_TYPE_FLAME_THROWER, m_Skill.m_ExtraAmmo);
		break;

		case WDSPickup::PICKUP_TYPE_PLASMARIFLE:
			pNewGun = new WDSGun(WDSGun::GUN_TYPE_PLASMA_RIFLE, m_Skill.m_ExtraAmmo);
		break;

		case WDSPickup::PICKUP_TYPE_MULTIPLASMAGUN:
			pNewGun = new WDSGun(WDSGun::GUN_TYPE_PLASMA_MULTI, m_Skill.m_ExtraAmmo);
		break;

		case WDSPickup::PICKUP_TYPE_PLASMAMINIGUN:
			pNewGun = new WDSGun(WDSGun::GUN_TYPE_PLASMA_MINIGUN, m_Skill.m_ExtraAmmo);
		break;

		case WDSPickup::PICKUP_TYPE_ROCKETLAUNCHER:
			pNewGun = new WDSGun(WDSGun::GUN_TYPE_ROCKET_LAUCHER, m_Skill.m_ExtraAmmo);
		break;

		case WDSPickup::PICKUP_TYPE_SEEKERROCKET:
			pNewGun = new WDSGun(WDSGun::GUN_TYPE_ROCKET_SEEKER, m_Skill.m_ExtraAmmo);
		break;

		case WDSPickup::PICKUP_TYPE_PLASMASHOTGUN:
			pNewGun = new WDSGun(WDSGun::GUN_TYPE_PLASMA_SHOTGUN, m_Skill.m_ExtraAmmo);
		break;

		case WDSPickup::PICKUP_TYPE_MINIROCKETSWARMER:
			pNewGun = new WDSGun(WDSGun::GUN_TYPE_ROCKET_MINI_SWARMERS, m_Skill.m_ExtraAmmo);
		break;

		case WDSPickup::PICKUP_TYPE_ROCKETMINIGUN:
			pNewGun = new WDSGun(WDSGun::GUN_TYPE_ROCKET_MINIGUN, m_Skill.m_ExtraAmmo);
		break;

		case WDSPickup::PICKUP_TYPE_PULSEGUN:
			pNewGun = new WDSGun(WDSGun::GUN_TYPE_PULSE, m_Skill.m_ExtraAmmo);
		break;

		case WDSPickup::PICKUP_TYPE_JACKHUMMER:
			pNewGun = new WDSGun(WDSGun::GUN_TYPE_JACK_HAMMER, m_Skill.m_ExtraAmmo);
		break;

		case WDSPickup::PICKUP_TYPE_IONRIFLE:
			pNewGun = new WDSGun(WDSGun::GUN_TYPE_ION_RIFLE, m_Skill.m_ExtraAmmo);
		break;

		case WDSPickup::PICKUP_TYPE_IONMINIGUN:
			pNewGun = new WDSGun(WDSGun::GUN_TYPE_MEAN_MINIGUN, m_Skill.m_ExtraAmmo);
		break;

		case WDSPickup::PICKUP_TYPE_IONCANNON:
			pNewGun = new WDSGun(WDSGun::GUN_TYPE_ION_CANNON, m_Skill.m_ExtraAmmo);
		break;

		case WDSPickup::PICKUP_TYPE_PLASMACANNON:
			pNewGun = new WDSGun(WDSGun::GUN_TYPE_PLASMA_CANNON, m_Skill.m_ExtraAmmo);
		break;

		case WDSPickup::PICKUP_TYPE_GAUSSSHOTGUN:
			pNewGun = new WDSGun(WDSGun::GUN_TYPE_GAUSS_SHOTGUN, m_Skill.m_ExtraAmmo);
		break;

		case WDSPickup::PICKUP_TYPE_IONSHOTGUN:
			pNewGun = new WDSGun(WDSGun::GUN_TYPE_ION_SHOTGUN, m_Skill.m_ExtraAmmo);
		break;
	}


	if(pNewGun)
	{
		UTIL_SAFE_DELETE(m_pGun);
		m_pGun = pNewGun;
	}

		
}

void	WDSPlayer::RenderUI(float Scale)
{ 
	m_UI.Render(Scale);  
	m_pGun->RenderUI(Scale);
}


void	WDSPlayer::LaserSight::Render(WDSPlayer* pPlayer, const math::Vec2& Offset, float Scale)
{
	if(!pPlayer->IsAlive())
		return;

	m_Sprite.m_Pos = pPlayer->GetPos() + ( pPlayer->m_Facing.GetForwardW2H() * pPlayer->m_Sprite.m_SizeOriginal.x * 0.5f ) - Offset;
	m_Sprite.m_Rotation = pPlayer->m_Facing.GetAngle() + 180.0f;
	m_Sprite.RenderRotated();
}

WDSPlayer::LaserSight::LaserSight()
{
	
	m_Sprite.Create("laser_scope");
}

